/*
Prepared by Nguyen Minh Huy
March 2012
*/
#include <stdio.h>

#include <Windows.h>

#include "bmp.h"

bool isBmpFile(FILE *f)
{
	if (f == NULL)
		return false;

	BmpCode code;
	fread(&code, sizeof(BmpCode), 1, f);

	return code.data[0] == 'B' && code.data[1] == 'M';
}

void readBmpHeader(FILE *f, BmpHeader &header)
{
	if (f == NULL)
		return;

	fread(&header, sizeof(BmpHeader), 1, f);
}

void printBmpHeader(BmpHeader header)
{
	printf("*** BMP Header ***\n");
	printf("- File Size  : %d byte(s)\n", header.fileSize);
	printf("- Reserved1  : %d\n", header.reserved1);
	printf("- Reserved2  : %d\n", header.reserved2);
	printf("- Data Offset: %d byte(s)\n", header.dataOffset);
}

void readBmpDib(FILE *f, BmpDib &dib)
{
	if (f == NULL)
		return;

	fread(&dib, sizeof(BmpDib), 1, f);
}

void printBmpDib(BmpDib dib)
{
	printf("*** BMP Dib ***\n");
	printf("- DIB Size               : %d byte(s)\n", dib.dibSize);
	printf("- Image Width            : %d\n", dib.imageWidth);
	printf("- Image Height           : %d\n", dib.imageHeight);
	printf("- Number of Color Planes : %d\n", dib.colorPlaneCount);
	printf("- Pixel Size             : %d bit(s)\n", dib.pixelSize);
	printf("- Compress Method        : %d\n", dib.compressMethod);
	printf("- Bitmap Size            : %d byte(s)\n", dib.bitmapByteCount);
	printf("- Horizontal Resolution  : %d\n", dib.horizontalResolution);
	printf("- Vertical Resolution    : %d\n", dib.verticalResolution);
	printf("- Number of Colors       : %d\n", dib.colorCount);
	printf("- Number of Impt Colors  : %d\n", dib.importantColorCount);
}

void readBmpPixelArray(FILE *f, BmpHeader header, BmpDib dib, Pixel24Array &data)
{
	if (f == NULL)
		return;

	fseek(f, header.dataOffset, 0L);

	data.lines = new Pixel24Line[dib.imageHeight];
	data.length = dib.imageHeight;

	for (int i = 0; i < data.length; i++)
		readBmpPixelLine(f, dib, data.lines[data.length - 1 - i]);
}

void readBmpPixelLine(FILE *f, BmpDib dib, Pixel24Line &line)
{
	if (f == NULL)
		return;

	line.pixels = new Pixel24[dib.imageWidth];
	line.length = dib.imageWidth;

	for (int i = 0; i < line.length; i++)
		fread(&line.pixels[i], sizeof(Pixel24), 1, f);

	skipBmpPadding(f, dib);
}

void skipBmpPadding(FILE *f, BmpDib dib)
{
	if (f == NULL)
		return;

	char padding[3];
	int  paddingCount = (dib.imageWidth * 3) % 4;

	if (paddingCount == 0)
		return;

	fread(&padding, paddingCount, 1, f);
}

void drawBmp(BmpDib dib, Pixel24Array data)
{
	HWND console = GetConsoleWindow();
	HDC hdc = GetDC(console);

	for (int i = 0; i < dib.imageHeight; i++)
		for (int j = 0; j < dib.imageWidth; j++)
		{
			Pixel24 pixel = data.lines[i].pixels[j];
			SetPixel(hdc, j, i, RGB(pixel.red, pixel.green, pixel.blue));
		}

	ReleaseDC(console, hdc);
}

void drawBmp(uint32_t imageWidth, uint32_t imageHeight, Pixel24Array data)
{
	HWND console = GetConsoleWindow();
	HDC hdc = GetDC(console);

	for (int i = 0; i < imageHeight; i++)
		for (int j = 0; j < imageWidth; j++)
		{
			Pixel24 pixel = data.lines[i].pixels[j];
			SetPixel(hdc, j, i, RGB(pixel.red, pixel.green, pixel.blue));
		}

	ReleaseDC(console, hdc);
}

void releaseBmpPixelArray(Pixel24Array data)
{
	for (int i = 0; i < data.length; i++)
		delete []data.lines[i].pixels;

	delete []data.lines;
}